import random
import string
import redis
from django.shortcuts import render
from rest_framework.views import APIView
from rest_framework.response import Response

from users.serializer import AddressSer
from .models import User,Address
from captcha.image import ImageCaptcha
from django.http import HttpResponse, JsonResponse
from django.contrib.auth.hashers import check_password, make_password
from rest_framework_jwt.utils import jwt_payload_handler, jwt_encode_handler
from django.contrib.auth import authenticate
from django.db.models import Q

# 生成图片验证码
class GenerateImageCode(APIView):
    def get(self, request, imagecodeid):
        """
        生成图片验证码
        1.接收前端传来的uuid，图片id
        2.使用随机模块生成：字符+数字的随机数，长度6
        3.使用capch模块生成图片
        4.返回生成的图片
        """
        # 生成的是数字加字符的字符串：eg：asWE23  we34WE
        salt = ''.join(random.sample(string.ascii_letters + string.digits,4))
        # 生成一张图片
        img = ImageCaptcha()
        # 把数字添加到图片上
        image = img.generate(salt)

        # 把生成的图片上的数字写入redis，便于后期校验
        # redis链接
        redis_cli = redis.Redis(host='localhost',port=6379)
        # 写入redis，把生成的图片上的数字写入redis
        # 要是用redis的哪一种数据类型? 字符串 为什么？ key/v  格式就满足需求
        # 写入到redis有效期
        imgId  = "img_{}".format(imagecodeid)
        redis_cli.setex(imgId,300, salt)

        return HttpResponse(image,content_type="imge/jpg")

# 校验图片验证码
class CheckLmageCode(APIView):
    def get(self,request):
        """
        图片验证码
        1.获取图片id
        2.查询
        3.对比
        """
        image_id = request.query_params.get('imageCodeID')
        image_code = request.query_params.get('imageCode')
        # 根据id查redis
        redis_cli = redis.Redis(host='localhost',port=6379)
        #
        result = redis_cli.get('img_{}'.format(image_id))
        if result:

            if result.decode().lower() != image_code.lower():
                return Response({'msg':'验证码输入错误'})
            else:
                return Response({'code':'200'})
        # 验证码过期
        else:
            return Response({'msg':'验证码过期'})

# 判断用户名是否重复
class CheckUsername(APIView):
    def get(self,request,name):
        """
        判断用户名是否重复
        1.获取前端传来的用户名
        2.校验，数据库中是否有此用户
        3.有的话说明数据已存在
        """
        # 从数据库查询
        rest = User.objects.filter(username=name).count()
        if rest > 0:
            # 说明用户已存在
            return Response({'msg':'用户已存在',"code":'400'})
        # 不存在
        return Response({"code":'200'})

# 判断是手机号
class CheckMobile(APIView):
    def get(self,request,mobile):
        """判断手机号"""
        rest = User.objects.filter(mobile=mobile).count()
        if rest > 0:
            # 说明用户已存在
            return Response({'msg': '手机号已存在', "code": '400'})
        # 不存在
        return Response({"code": '200'})

# 注册
class UserRegister(APIView):
    def post(self,request):
        """
        注册业务逻辑（实现思路）:
        1.获取数据，拿过来的和数据库里的作比较
        2.如果字段一样比较，注册成功，写入数据库
        3.是否勾选
        """
        user_name = request.data.get('userName')
        pwd = request.data.get('pwd')
        mobile = request.data.get('mobile')
        agree = request.data.get('agree')
        # 后端一定要校验
        # 只要有一个为空就报错
        if not all([user_name,pwd,mobile,agree]):
            return Response({'msg':'请完善注册信息','code':'400'})

        if not agree:
            # 说明没有同意协议
            return Response({'msg':'请勾选协议'})
        # 写入数据库
        # create（）写入数据库时，密码是铭文存储
        User.objects.create_user(username=user_name,password=pwd,mobile=mobile)
        return Response({'msg':'注册成功',"code":'201'})

# 登陆
class Login(APIView):
    # 方式二
    def post(self,request):
        """
        登陆
        1.获取前端的用户和密码
        2.对用户和密码进行校验
        3.成功返回200
        4.不成功返回400
        """
        user_name = request.data.get('user')
        pwd = request.data.get('pwd')
        # 对前端传来的密码进行校验
        # 1. 用户名是否在数据库中
        try:
            user = User.objects.get(Q(username=user_name) | Q(mobile=user_name))
        except User.DoesNotExist as e:
            return Response({'msg':"用户不存在","code":'400'})
        # 2. 如果存在检验是否一致
        # 数据库里的数据是密文，前端是明文
        #
        is_correct = check_password(pwd,user.password)
        # 返回true，说明匹配
        if is_correct:
            # 生成token，把token返回
            payload = jwt_payload_handler(user)
            #
            token = jwt_encode_handler(payload)
            # 把token写入cookie，便于退出
            resp = Response({'msg':'登陆成功','code':200,'user':{"userName":user.username},"token":token})
            # 设置cookie中
            resp.set_cookie('token',token)
            return resp
        else:
            return Response({'msg':'用户或密码失败','code':'400'})
    # 方法一
    # def post(self,request):
    #     user_name = request.data.get('user')
    #     pwd = request.data.get('pwd')
    #
    #     # 校验
    #     user = authenticate(username=user_name,password=pwd)
    #     if user:
    #         payload = jwt_payload_handler(user)
    #         token = jwt_encode_handler(payload)
    #         return Response({'msg': '登陆成功', 'code': 200, 'user': {"userName": user.username}})
    #     else:
    #         return Response({'msg':'用户或密码失败','code':'400'})

# 退出登录
class Logout(APIView):
    def post(self,request):
        """退出登录"""
        # 删除cookie
        token = request.COOKIES.get('token')
        if token:
            del token
        return Response({'msg':'退出成功',"code":200})


# 用户信息展示
class UserInfo(APIView):
    def post(self,request):

        name = request.data.get('user').get('userName')
        # 查询用户信息和用户的收货地址信息
        try:
            user = User.objects.get(username=name)
        except Exception as e:
            return Response({'msg':"请先登录","code":400})
        # 返回用户信息
        """
        {"mobile":xxxx,"name":q3rry,, }
        """
        addresses = user.address_set.all()
        # add_ser = AddressSer(addresses, many=True)
        user_addr = []
        for addr in addresses:
            user_addr.append(AddressSer(addr).data)

        data = {
            "username":user.username,
            "mobile":user.mobile,
            "addresses":user_addr
        }

        return JsonResponse({"msg":"获取用户信息成功","code":200,"userInfo":data})

# 添加收货地址
class AddAddress(APIView):
    def post(self, request):
        """添加收货地址"""
        name = request.data.get('user').get('userName')
        # 查询用户信息和用户的收货地址信息
        try:
            user = User.objects.get(username=name)
        except Exception as e:
            return Response({'msg': "请先登录", "code": 400})
        receiver = request.data.get('receiver')
        receive_mobile = request.data.get('receive_mobile')
        receive_addr = request.data.get('receive_addr')
        is_default = request.data.get('is_default')
        if not all([receive_addr, receiver, receive_mobile, is_default]):
            # 此时数据不全
            return Response({'msg': "请完善地址信息", "code": 400})
        add = Address.objects.create(user_id=user.id, is_default=is_default, receiver=receiver,
                                     receive_addr=receive_addr, receive_mobile=receive_mobile)
        ser = AddressSer(add)
        return Response({"msg": "添加收货地址成功", "code": 200, "addr": ser.data})


# 修改用户信息
class UpdateUserInfo(APIView):
    def post(self, request):
        name = request.data.get('user').get('userName')
        # 查询用户信息和用户的收货地址信息
        try:
            user = User.objects.get(username=name)
        except Exception as e:
            return Response({'msg': "请先登录", "code": 400})
        phone = request.data.get('phone')
        # 前端传来的用户地址信息
        print(phone)
        addr_list = request.data.get('addrs')
        # 更新用户的手机号
        user.mobile = phone
        user.save()
        # 查询出当前用户的所有的地址
        print('111',addr_list)
        for new_addr in addr_list:
            print(">>>>", new_addr)
            # 判断是否有更新, 若没有返回对象,要更新, 若返回的有对象,不用更新
            addr = Address.objects.filter(id=new_addr.get('id'),
                                          receiver=new_addr.get("receiver"),
                                          receive_mobile=new_addr.get("receive_mobile"),
                                          receive_addr=new_addr.get("receive_addr"),
                                          )
            print(addr)
            if not addr:
                addrs = Address.objects.get(id=new_addr.get('id'))
                addrs.receiver = new_addr.get("receiver")
                addrs.receive_mobile = new_addr.get("receive_mobile")
                addrs.receive_addr = new_addr.get("receive_addr")
                addrs.save()

        return Response({'msg': "更新信息成功", "code": 200})


# 删除地址
class DelAddressInfo(APIView):
    def post(self,request):
        add_id = request.data.get('addr_id')
        try:
            address = Address.objects.get(id=add_id)
        except Exception as e:
            return Response({'msg':'获取地址信息失败',"code":400})
        address.delete()
        return Response({'msg':'删除成功','code':200})


# 修改密码
class UpdatePassword(APIView):
    def post(self, request):
        name = request.data.get('user')
        old_pwd = request.data.get('originPw')
        new_pwd = request.data.get('newPw')
        confirm_pwd = request.data.get('confirmNewPw')
        if new_pwd != confirm_pwd:
            return Response({"msg": '输入的两次密码不一致,请重新输入', "code": 400})
        if old_pwd == new_pwd:
            return Response({"msg": '新密码和旧密码一样,请重新输入', "code": 400})
        try:
            user = User.objects.get(username=name)
        except Exception  as e:
            return Response({"msg": "获取用户失败", "code": 400})
        user.password = make_password(new_pwd)
        user.save()
        return Response({'msg': "修改密码成功", "code": 200})


